package com.mall.shopping.services;

import com.github.pagehelper.PageHelper;
import com.mall.commons.tool.exception.ExceptionUtil;
import com.mall.shopping.IHomepageService;
import com.mall.shopping.constants.ShoppingRetCode;
import com.mall.shopping.converter.ContentConverter;
import com.mall.shopping.converter.ProductCateConverter;
import com.mall.shopping.converter.ProductConverter;
import com.mall.shopping.dal.entitys.*;
import com.mall.shopping.dal.persistence.ItemCatMapper;
import com.mall.shopping.dal.persistence.ItemMapper;
import com.mall.shopping.dal.persistence.PanelContentMapper;
import com.mall.shopping.dal.persistence.PanelMapper;
import com.mall.shopping.dto.*;
import com.mall.shopping.utils.ProjectUtils;
import com.mall.user.constants.SysRetCodeConstants;
import lombok.SneakyThrows;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @program: project4-mall
 * @time: 2021/10/31
 * @author: yangshuai
 **/

/**
 * 主页显示
 */
@Service
public class IHomepageServiceImpl implements IHomepageService {

    @Autowired
    PanelMapper panelMapper;

    @Autowired
    PanelContentMapper panelContentMapper;

    @Autowired
    ItemCatMapper itemCatMapper;

    // 转换器
    @Autowired
    ProductConverter productConverter;

    // 转换器
    @Autowired
    ContentConverter contentConverter;

    // 转换器
    @Autowired
    ProductCateConverter productCateConverter;

    // 要使用关键字搜索商品，引入itemMapper
    @Autowired
    ItemMapper itemMapper;


    /**
     * 主页显示
     * @return
     */
    @Override
    public HomePageResponse homepage() {

        HomePageResponse response = new HomePageResponse();
        PanelDto panelDto = null;
        Set<PanelDto> panelContentItemDtos = new HashSet<PanelDto>();

        try {
            // 获取类目信息
            List<Panel> panels = panelMapper.selectPanel();
            // 通过类目ID获取该类目的内容
            for (Panel panel : panels) {
                // 查询类目关联商品信息
                List<PanelContentItem> panelContentItems = panelContentMapper.selectPanelContentAndProductWithPanelId(panel.getId());
                // 格式转换
                List<PanelContentItemDto> panelContentItemDto = productConverter.panelContentItems2PanelContentItemDto(panelContentItems);
                panelDto = new PanelDto(panel.getId(),panel.getName(),panel.getType(),panel.getSortOrder(),panel.getPosition(),panel.getLimitNum(),panel.getStatus(),panel.getRemark(),panelContentItemDto);
                panelContentItemDtos.add(panelDto);
            }

            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            response.setPanelContentItemDtos(panelContentItemDtos);

        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            response.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }

        return response;
    }


    /**
     * 导航栏显示
     * @return
     */
    @Override
    public NavListResponse selectNavigation() {

        NavListResponse response = new NavListResponse();

        try {
            // 查询导航栏信息
            List<PanelContent> panelContents = panelContentMapper.selectPanelContent();
            // 格式转换
            List<PanelContentDto> panelContentDtos = contentConverter.panelContents2Dto(panelContents);
            // 返回信息
            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            response.setPannelContentDtos(panelContentDtos);
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            response.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }

        return response;
    }

    /**
     * 列举所有商品种类
     * @return
     */
    @Override
    public AllProductCateResponse selectAllProductCate() {

        AllProductCateResponse response = new AllProductCateResponse();
        try {
            // 查询所有商品种类
            List<ItemCat> itemCats = itemCatMapper.selectItemCate();
            // 格式转换
            List<ProductCateDto> productCateDtos = productCateConverter.items2Dto(itemCats);

            response.setCode(ShoppingRetCode.SUCCESS.getCode());
            response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
            response.setProductCateDtoList(productCateDtos);
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(ShoppingRetCode.DB_EXCEPTION.getCode());
            response.setMsg(ShoppingRetCode.DB_EXCEPTION.getMessage());
        }

        return response;
    }


    /**
     *  按关键字搜索商品
     *
     * @param searchProductRequest
     * @return
     */
    @SneakyThrows
    @Override
    public SearchProductResponse searchProduct(SearchProductRequest searchProductRequest) {
        SearchProductResponse searchProductResponse = new SearchProductResponse();
        if(searchProductRequest.getPage() != null || searchProductRequest.getSize() != null){
            // 分页
            PageHelper.startPage(searchProductRequest.getPage(),searchProductRequest.getSize());
        }

        try {
            // 获取关键字
            String keyword = searchProductRequest.getKey();
            // 按关键字搜索相似度高的商品
            searchProductResponse = searchGoodsByKeyword(keyword);
            // TODO 按关键字搜索关联的商品
            if(searchProductResponse.getTotal() == 0){
                // 没有搜索到
                searchProductResponse.setCode(SysRetCodeConstants.DATA_NOT_EXIST.getCode());
                searchProductResponse.setMsg(SysRetCodeConstants.DATA_NOT_EXIST.getMessage());
                return searchProductResponse;
            }
            // 成功搜索到
            searchProductResponse.setCode(SysRetCodeConstants.SUCCESS.getCode());
            searchProductResponse.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionUtil.handlerException4biz(searchProductResponse,e);
        }

        return searchProductResponse;
    }

    // 搜索商品
    public SearchProductResponse searchGoodsByKeyword(String keyword) {
        SearchProductResponse searchProductResponse = new SearchProductResponse();

//        SqlSession sqlSession = MybatisUtils.getSqlSession();
//        GoodDao goodDao = sqlSession.getMapper(GoodDao.class);
        /*
        可以优化的地方还有很多:
        1. 如果商品数量比较少, 可以将商品名字全部查出来, 然后计算匹配度
        2. 也可以一边向数据库查询,一边计算匹配度, 同时统计返回值中符合规定匹配度的 条目个数(应该是一页的数量),
         如果条目个数够了, 就停止查询, 需要用户点击"滑动查看更多, 或 者下一页"后,才继续查询
        */

        // 先使用普通的模糊查询, 如果没有查到, 就使用加强的模糊查询
        List<Item> searchGoodsList = itemMapper.selectGoodsByKeyword(keyword);


        if (searchGoodsList.size() == 0){
            // 使用加强模糊查询
            // 先获取所有的商品及id(待优化), GoodsList中仅有id和name两个字段
            List<GoodsIdAndNameDto> allGoodsIdAndNameList = itemMapper.getAllGoodsIdAndNameList();
            // 声明id数组,以及名字相似度数组
            int[] idArray = new int[300];
            double[] simlarityArray = new double[300];
            // 声明数组中商品的数量
            int length = 0;
            // 使用正则表达式, 判断keywords是否全部由字母组成, 如果是, 就触发拼音检 索, 否则就使用加强模糊查询
            boolean isChars = keyword.matches("[a-zA-Z]*");
            //遍历商品列表
            for (GoodsIdAndNameDto goodsIdAndName: allGoodsIdAndNameList) {
                // 如果商品是广告位的id或name, 就将相似度设置为1,便于优先展示
                if ("广告位招租".equals(goodsIdAndName.getTitle())){
                    idArray[length] = goodsIdAndName.getId();
                    simlarityArray[length] = 1;
                    length++;
                    continue;
                }
                // 加入拼音功能, 返回的是熟练度
                boolean contains = false;
                //商品名字中是否包含keywords的标志
                if (isChars) {
                    // 如果全是字母， 使用拼音检索功能
                    contains = spellContains(keyword, goodsIdAndName.getTitle());
                }
                if (contains){
                    // 如果包含, 就将相似度设置为1, 优先展示
                    // 同时,保存相似度与id, 便于排序
                    idArray[length] = goodsIdAndName.getId();
                    simlarityArray[length] = 1;
                    length++;
                }else {
                    // 加强模糊搜索
                    // 使用相似度算法比较keyword与商品名字的相似程度
                    Double tempSimlarity = ProjectUtils.SimlarityString(keyword, goodsIdAndName.getTitle());
                    if (tempSimlarity >= ProjectUtils.goodsSimilarity) {
                        // 如果大于配置文件中的相似度阈值, 就保存id与相似度
                        // 这里的配置文件中的相似度为0.5
                        idArray[length] = goodsIdAndName.getId();
                        simlarityArray[length] = tempSimlarity;
                        length++;
                    }
                }
            }
            // 排序相似度,降序
            idArray = getIdArray(simlarityArray, idArray, length);
            searchGoodsList = new ArrayList<>();
            // 遍历id数组, 根据相似度顺序将商品添加到列表中
            for (int i = 0; i < length; i++) {
                Item aGood = itemMapper.selectByPrimaryKey(idArray[i]);
                searchGoodsList.add(aGood);
            }
        }if (searchGoodsList == null){
            searchGoodsList = new ArrayList<>();
        }
        // 如果这时商品列表中只有一个商品, 判断是不是广告, 如果只有广告,说明没有达到相 似度阈值的商品, 替换成关爱页面
        if (searchGoodsList.size() == 1){
            Item searchGoodsVO = searchGoodsList.get(0);
            if ("广告位招租".equals(searchGoodsVO.getTitle())){
                searchGoodsList.remove(0);
                // 关爱页面的id
                Item aGood = itemMapper.selectByPrimaryKey(30);
                searchGoodsList.add(aGood);
            }
        }

        // List<Item>转化为List<ProductDto>
//        List<ProductDto> productDtoList = new ArrayList<>();
//        for (Item item : searchGoodsList) {
//            ProductDto productDto = new ProductDto(item.getId(),item.getPrice(),item.getTitle(),
//                    item.getSellPoint(),item.getImage());
//            productDtoList.add(productDto);
//        }

        // List<Item>转化为List<ProductDto>
        List<ProductDto> productDtoList = productConverter.items2Dto(searchGoodsList);

        // 给返回值赋值
        searchProductResponse.setData(productDtoList);
        searchProductResponse.setTotal((long) productDtoList.size());

        return searchProductResponse;
    }

    //判断商品名字转化为拼音后是否包含keyword
    private boolean spellContains(String keyword, String name) {
        System.out.println(name);
        String s = ProjectUtils.cn2Spell(name);
        System.out.println(s);
        return s.contains(keyword);
    }

    // 将相似度数组与id数组同步排序
    private int[] getIdArray(double[] simlarityArray, int[] idArray, int length) {
        for (int i = 0; i < length - 1; i++) {
            for (int j = 0; j < length - 1 - i; j++) {
                int temp1 = 0;
                //相似商品推荐
                double temp2 = 0;
                if (simlarityArray[j] < simlarityArray[j + 1]) {
                    // 交换
                    temp2 = simlarityArray[j];
                    simlarityArray[j] = simlarityArray[j+1];
                    simlarityArray[j+1] = temp2;
                    temp1 = idArray[j];
                    idArray[j] = idArray[j + 1];
                    idArray[j + 1] = temp1;
                }
            }
        }
        return idArray;
    }


    /**
     *  获取相似商品
     *
     */
//    private SearchProductResponse getGoodsByType(){
//        String typeId = request.getParameter("typeId");
//        int id = Integer.parseInt(typeId);
//        // 由于前端getGoodsByType方法只能传递过来一个typeId,所以并不能拿到当前商品的id,也就无法根据当前商品进行推荐.但是打开客户端打开这个页面时,也调用了其他的api,  这样就可以在其他api中将当前商品的id存到session中,为了保证其他的api先执行,这里线程休眠0.1s
//        Thread.sleep(100);
//        try {
//            int curId = (int) request.getSession().getAttribute("curId");
//        }catch (NullPointerException e){
//            // 如果是空指针异常, 说明在使用getGoodsByType这个接口的时候并没有同时调用其他能保存商品id的接口, 比如后台使用这个接口的时候, 就是单独地使用这个接口
//            // 这时就使用goodsService中普通的getGoodsByType(id),否则使用getGoodsByType(int typeId, Integer curId)
//            List<GoodVO> goodsByType = goodsService.getGoodsByType(id);
//            ResultVO resultVO = new ResultVO(0, goodsByType, null);
//            response.getWriter().println(gson.toJson(resultVO));
//            return;
//        }
//        // 拿到当前商品的id后,就可以使用getGoodsByType(int typeId, Integer curId)
//        //方法进行相似商品查询了
//        int curId = (int) request.getSession().getAttribute("curId");
//        List<GoodVO> goodsByType = goodsService.getGoodsByType(id, curId);
//        request.getSession().removeAttribute("curId");
//        ResultVO resultVO = new ResultVO(0, goodsByType, null);
//        response.getWriter().println(gson.toJson(resultVO));
//    }
//}
//
//
//    public List<GoodVO> getGoodsByType(int typeId, Integer curId) {
//
//
//        // 获取同一类别下所有商品的id与name
//        List<GoodsList> goodsList = goodDao.getGoodsList(typeId);
//
//        int[] idArray = new int[30];
//        double[] simlarityArray = new double[30];
//        String[] nameArray = new String[30];
//        int length = 0;
//        String curName = null;
//        for (GoodsList list : goodsList) {
//            if (list.getId() == curId){
//                curName = list.getName();
//            }
//            idArray[length] = list.getId();
//            nameArray[length] = list.getName();
//            length++;
//        }
//
//        // 计算相似度
//        for (int i = 0; i < length; i++) {
//            simlarityArray[i] = ProjectUtils.SimlarityString(curName, nameArray[i]);
//        }
//
//        // 排序相似度, 快速排序
//        //	idArray = sort(simlarityArray, idArray, length);
//        // 排序相似度, 冒泡排序
//        idArray = getIdArray(simlarityArray, idArray, length);
//        List<GoodPOJO> goodsByType = new ArrayList<>();
//        // 遍历id数组,根据相似读加入到list并返回
//        for (int i = 0; i < length; i++) {
//            GoodPOJO aGood = goodDao.getGoodsByType2(typeId, idArray[i]);
//            goodsByType.add(aGood);
//        }
//
//        ArrayList<GoodVO> goodOVS = new ArrayList<>();
//        for (GoodPOJO goodPOJO : goodsByType) {
//            goodOVS.add(new GoodVO(goodPOJO.getId(), FileUploadUtils.getAppAdress() + goodPOJO.getImg(), goodPOJO.getName(), goodPOJO.getPrice(),
//                    goodPOJO.getTypeId(), goodPOJO.getStockNum())); 68	}
//        return goodOVS;
//    }


}
